
#ifndef GMACHINE_HEADER_GPROCESSOR_H
#define	GMACHINE_HEADER_GPROCESSOR_H

#include "GProfile.h"
#include "GStacker.h"
#include "GRegister.h"

#include <cassert>

namespace GMachine
{
	/*
	class IPathnode
	{
	public:
		enum PASSRULE {RULE_EQ, RULE_GT, RULE_LS, RULE_GE, RULE_LE, RULE_NE, RULE_NN};
	protected:
		IPathnode(const PASSRULE rule):m_passrule(rule){}
	protected:
		const PASSRULE	m_passrule;
		void		*	m_codebuff;
		unsigned int	m_buffsize;
		IPathnode	*	m_missnode;
		IPathnode	*	m_nextnode;
	};

	template <typename T>
	class EQPathnode:public IPathnode
	{
	public:
		EQPathnode(const T& stub):m_stub(stub) {}
	public:
		bool getcodes(const T& passport, void *& buffer, unsigned int & length)
		{
			if (passport == m_stub)
			{
				//buffer = m_codebuff;
				//length = m_buffsize;
				return m_nextnode->getcodes(...);
			}
			else
			{
				return m_missnode->getcodes(passport, buffer, length);
			}
		}

		bool perform(const T& passport)
		{
			if (passport == m_stub)
			{
				//execute m_codebuff
				return m_nextcode->perform(...);
			}
			else
			{
				return m_missnode->perform(passport);
			}
		}
	}
	*/
	/*
	template <typename T>
	class GPathnode:public IPathnode
	{
	public:
		GPathnode(const PASSRULE rule, const T& stub):IPathnode(rule), m_stub(stub){}
	public:
		void GetCodes(const T& passport, void*& buffer, unsigned int & length)
		{
			
			switch(this->m_passrule)
			{
			case RULE_EQ:
				if (passport == this->m_stub)
				{
					buffer = this->m_codebuff;
					length = this->m_buffsize;
				}
				else
				{
					m_missnode->GetCodes(passport, buffer, length);
				}
				break;
			case RULE_GT:
				(passport < this->m_stub || passport == this->m_stub)
					? m_missnode->Perform()
					: m_passnode->Perform();
				break;
			case RULE_LS:
				passport < this->m_stub
					? m_passnode->Perform()
					: m_missnode->Perform();
				break;
			case RULE_GE:				
				passport < this->m_stub
					? m_missnode->Perform()
					: m_passnode->Perform();
				break;
			case RULE_LE:
				(passport < this->m_stub || passport == this->m_stub)
					? m_passnode->Perform()
					: m_missnode->Perform();
				break;
			case RULE_NE:
				passport == this->m_stub
					? m_missnode->Perform()
					: m_passnode->Perform();
				break;
			case RULE_NN:

			};
		}
	private:
		const T m_stub;
	};
	*/


	///////////////////////////////////////////////////////////////
	// Processor
	///////////////////////////////////////////////////////////////
	class GProcessor
	{
		template<U8> friend struct TraitsOfCode;
	public:
		GProcessor(unsigned int stacksize = 8192):stk(stacksize) { return; }
		virtual ~GProcessor() { return; }
	public:	
		int Process(void * buffer, int size);
		int Suspend() { return 0; }
		int Resume() { return 0; }
	public:	// just for debug
		GStacker	stk;
		GRegister	reg;
	};


	////////////////////////////////////////////////////////////////////
	// Traits and executions
	////////////////////////////////////////////////////////////////////
	template<U8 codename> struct TraitsOfCode 
	{
		enum { codesize = 1 };
		static inline void Execution(GProcessor &, U8 *&)
		{ 
			//cout<<"invalid instruction.["<<int(codename)<<"]"<<endl;
			return; 
		}
	};

	////////////////////////////////////////////////////////////////////
	// Specialization
	////////////////////////////////////////////////////////////////////
	template<> struct TraitsOfCode<Codename::noop> 
	{ 
		enum { codesize = 1 };
		static inline void Execution(GProcessor & /*processor*/, U8 *& /*ptr*/)
		{
			return;
		}
	};

	template<> struct TraitsOfCode<Codename::init> 
	{ 
		enum { codesize = 6 }; 
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
			return;
		}
	};

	template<> struct TraitsOfCode<Codename::halt> 
	{ 
		enum { codesize = 3 }; 
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
			return;
		}
	};

	template<> struct TraitsOfCode<Codename::vcall> 
	{ 
		enum { codesize = sizeof(U8) + sizeof(U32) }; // [1][4] <=>[CODE][closure id]
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
			U32* idPtr = (U32*)(ptr + 1);
			CodeBlock * block = processor.GetClosure(idPtr);
			if (block != NULL)
			{
				*ptr = Codename::rcall;
				*idPtr = block->id;
			}
			else
			{
				processor->Suspend();
				processor->OnInvokeClosure(*idPtr);
			}
			return;
		}
	};

	template<> struct TraitsOfCode<Codename::rcall> 
	{ 
		enum { codesize = sizeof(U8) + sizeof(U32) }; 
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
			return;
		}
	};

	template<> struct TraitsOfCode<Codename::rmov> 
	{ 
		enum { codesize = 4 }; 
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
		}
	};

	template<> struct TraitsOfCode<Codename::imov> 
	{ 
		enum {
			codesize = TraitsOfCell<Cellname::RCELL>::size
				+ TraitsOfCell<Cellname::RCELL>::size
				+ TraitsOfCell<Cellname::GCELL>::size
		};
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
			processor.reg.G[ptr[1]] = *((IntegerObject*)(ptr + 2));
		}
	};

	template<> struct TraitsOfCode<Codename::load>
	{
		enum { codesize = 3 }; 
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
		}
	};

	template<> struct TraitsOfCode<Codename::save> 
	{ 
		enum { codesize = 3 }; 
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
		}
	};

	template<> struct TraitsOfCode<Codename::allo> 
	{ 
		enum { codesize = 3 }; 
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
		}
	};

	template<> struct TraitsOfCode<Codename::free> 
	{ 
		enum { codesize = 3 }; 
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
		}
	};

	template<> struct TraitsOfCode<Codename::vmid> 
	{ 
		enum { codesize = 3 };
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
		}
	};

	template<> struct TraitsOfCode<Codename::guid> 
	{ 
		enum { codesize = 3 };
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
		}
	};

	template<> struct TraitsOfCode<Codename::radd> 
	{ 
		enum { codesize = 3 };
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
			return;
		}
	};

	template<> struct TraitsOfCode<Codename::iadd> 
	{ 
		enum { codesize = 3 };
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
			return;
		}
	};

	template<> struct TraitsOfCode<Codename::vadd> 
	{
		enum { codesize = 3 };
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
			return;
		}
	};

	template<> struct TraitsOfCode<Codename::rdec> 
	{ 
		enum { codesize = 3 };
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
			return;
		}
	};

	template<> struct TraitsOfCode<Codename::idec> 
	{ 
		enum { codesize = 3 };
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
			return;
		}
	};

	template<> struct TraitsOfCode<Codename::vdec> 
	{ 
		enum { codesize = 3 };
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
			return;
		}
	};

	template<> struct TraitsOfCode<Codename::rmul> 
	{ 
		enum { codesize = 3 };
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
			return;
		}
	};

	template<> struct TraitsOfCode<Codename::imul> 
	{ 
		enum { 
			codesize = TraitsOfCell<Cellname::RCELL>::size 
				+ TraitsOfCell<Cellname::RCELL>::size 
				+ TraitsOfCell<Cellname::GCELL>::size 
		};
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
			processor.reg.G[ptr[1]] *= *((IntegerObject*)(ptr + 2));
			return;
		}
	};

	template<> struct TraitsOfCode<Codename::vmul> 
	{ 
		enum { codesize = 3 };
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
			return;
		}
	};

	template<> struct TraitsOfCode<Codename::rdiv> 
	{
		enum { codesize = 3 };
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
			return;
		}
	};

	template<> struct TraitsOfCode<Codename::idiv> 
	{ 
		enum { codesize = 3 };
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
			return;
		}
	};

	template<> struct TraitsOfCode<Codename::vdiv> 
	{ 
		enum { codesize = 3 };
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
			return;
		}
	};

	template<> struct TraitsOfCode<Codename::floor> 
	{ 
		enum { codesize = TraitsOfCell<Cellname::RCELL>::size 
				+ TraitsOfCell<Cellname::RCELL>::size 
				+ TraitsOfCell<Cellname::FCELL>::size };
		static inline void Execution(GProcessor & processor, U8 *& ptr)
		{
			processor.reg.F[ptr[1] - Regname::F0.regid] = floor(*(FloatingObject*)(ptr + 2));
			return;
		}
	};

	///////////////////////////////////////////////////////////////
	//	GProcessor implementation
	///////////////////////////////////////////////////////////////
	inline int GProcessor::Process(void * buffer, int length)
	{
		assert(length > 0 && buffer != 0);

		if (length <= 0 || buffer == 0) return 0;

		U8*	codePtr = (U8*)buffer;
		U8*	codeEnd = (U8*)buffer + length;
	//---------------------------------------------------------
	//	Macro for define process of code
#	define DOCODE(code)											\
	case code:													\
	if (codePtr + TraitsOfCode<code>::codesize <= codeEnd) {	\
		TraitsOfCode<code>::Execution(*this, codePtr); break;	\
	} else return (codeEnd - codePtr);
	//---------------------------------------------------------
		for(;;)	switch (*codePtr) {
			DOCODE(0);  DOCODE(1);  DOCODE(2);  DOCODE(3);	DOCODE(4);  DOCODE(5);  DOCODE(6);  DOCODE(7);
			DOCODE(8);  DOCODE(9);  DOCODE(10); DOCODE(11); DOCODE(12); DOCODE(13); DOCODE(14); DOCODE(15);
			DOCODE(16); DOCODE(17);	DOCODE(18); DOCODE(19);	DOCODE(20); DOCODE(21); DOCODE(22); DOCODE(23);
			DOCODE(24); DOCODE(25); DOCODE(26); DOCODE(27); DOCODE(28); DOCODE(29); DOCODE(30); DOCODE(31);
			DOCODE(32); DOCODE(33); DOCODE(34); DOCODE(35); DOCODE(36); DOCODE(37); DOCODE(38); DOCODE(39);
			DOCODE(40); DOCODE(41); DOCODE(42); DOCODE(43); DOCODE(44); DOCODE(45); DOCODE(46); DOCODE(47);
			DOCODE(48); DOCODE(49); DOCODE(50); DOCODE(51); DOCODE(52); DOCODE(53); DOCODE(54); DOCODE(55);
			DOCODE(56); DOCODE(57); DOCODE(58); DOCODE(59); DOCODE(60); DOCODE(61); DOCODE(62); DOCODE(63);
			DOCODE(64); DOCODE(65); DOCODE(66); DOCODE(67); DOCODE(68); DOCODE(69); DOCODE(70); DOCODE(71);
			DOCODE(72); DOCODE(73); DOCODE(74); DOCODE(75); DOCODE(76); DOCODE(77); DOCODE(78); DOCODE(79);
			DOCODE(80); DOCODE(81); DOCODE(82); DOCODE(83); DOCODE(84); DOCODE(85); DOCODE(86); DOCODE(87);
			DOCODE(88); DOCODE(89); DOCODE(90); DOCODE(91); DOCODE(92); DOCODE(93); DOCODE(94); DOCODE(95);
			DOCODE(96); DOCODE(97); DOCODE(98); DOCODE(99); DOCODE(100);DOCODE(101);DOCODE(102);DOCODE(103);
			DOCODE(104);DOCODE(105);DOCODE(106);DOCODE(107);DOCODE(108);DOCODE(109);DOCODE(110);DOCODE(111);
			DOCODE(112);DOCODE(113);DOCODE(114);DOCODE(115);DOCODE(116);DOCODE(117);DOCODE(118);DOCODE(119);
			DOCODE(120);DOCODE(121);DOCODE(122);DOCODE(123);DOCODE(124);DOCODE(125);DOCODE(126);DOCODE(127);
			DOCODE(128);DOCODE(129);DOCODE(130);DOCODE(131);DOCODE(132);DOCODE(133);DOCODE(134);DOCODE(135);
			DOCODE(136);DOCODE(137);DOCODE(138);DOCODE(139);DOCODE(140);DOCODE(141);DOCODE(142);DOCODE(143);
			DOCODE(144);DOCODE(145);DOCODE(146);DOCODE(147);DOCODE(148);DOCODE(149);DOCODE(150);DOCODE(151);
			DOCODE(152);DOCODE(153);DOCODE(154);DOCODE(155);DOCODE(156);DOCODE(157);DOCODE(158);DOCODE(159);
			DOCODE(160);DOCODE(161);DOCODE(162);DOCODE(163);DOCODE(164);DOCODE(165);DOCODE(166);DOCODE(167);
			DOCODE(168);DOCODE(169);DOCODE(170);DOCODE(171);DOCODE(172);DOCODE(173);DOCODE(174);DOCODE(175);
			DOCODE(176);DOCODE(177);DOCODE(178);DOCODE(179);DOCODE(180);DOCODE(181);DOCODE(182);DOCODE(183);
			DOCODE(184);DOCODE(185);DOCODE(186);DOCODE(187);DOCODE(188);DOCODE(189);DOCODE(190);DOCODE(191);
			DOCODE(192);DOCODE(193);DOCODE(194);DOCODE(195);DOCODE(196);DOCODE(197);DOCODE(198);DOCODE(199);
			DOCODE(200);DOCODE(201);DOCODE(202);DOCODE(203);DOCODE(204);DOCODE(205);DOCODE(206);DOCODE(207);
			DOCODE(208);DOCODE(209);DOCODE(210);DOCODE(211);DOCODE(212);DOCODE(213);DOCODE(214);DOCODE(215);
			DOCODE(216);DOCODE(217);DOCODE(218);DOCODE(219);DOCODE(220);DOCODE(221);DOCODE(222);DOCODE(223);
			DOCODE(224);DOCODE(225);DOCODE(226);DOCODE(227);DOCODE(228);DOCODE(229);DOCODE(230);DOCODE(231);
			DOCODE(232);DOCODE(233);DOCODE(234);DOCODE(235);DOCODE(236);DOCODE(237);DOCODE(238);DOCODE(239);
			DOCODE(240);DOCODE(241);DOCODE(242);DOCODE(243);DOCODE(244);DOCODE(245);DOCODE(246);DOCODE(247);
			DOCODE(248);DOCODE(249);DOCODE(250);DOCODE(251);DOCODE(252);DOCODE(253);DOCODE(254);DOCODE(255);
		}
	//---------------------------------------------------------
#	undef DOCODE
	//---------------------------------------------------------
	}	
	///////////////////////////////////////////////////////////////
}

#endif	//ifndef GMACHINE_HEADER_GPROCESSOR_H
